﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Model
{
    /// <summary>
    /// 缓存数据
    /// </summary>
    public class BufferData
    {
        private readonly BufferDataType _dataType;
        /// <summary>
        /// 数据存放类型
        /// </summary>
        public BufferDataType DataType
        {
            get { return this._dataType; }
        }

        private readonly byte[] _bytes = null;
        /// <summary>
        /// 内存数据
        /// </summary>
        public byte[] Bytes
        {
            get
            {
                if (this._dataType == BufferDataType.Bytes)
                {
                    return this._bytes;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.Bytes.ToString()}");
                }
            }
        }


        private readonly string _filePath = null;
        /// <summary>
        /// 文件数据
        /// </summary>
        public string FilePath
        {
            get
            {
                if (this._dataType == BufferDataType.File)
                {
                    return this._filePath;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.File.ToString()}");
                }
            }
        }

        private readonly Stream _stream;
        /// <summary>
        /// 数据流
        /// </summary>
        public Stream Stream
        {
            get
            {
                if (this._dataType == BufferDataType.Stream)
                {
                    return this._stream;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.Stream.ToString()}");
                }
            }
        }

        private readonly BinaryReader _reader;
        /// <summary>
        /// 二进制读取器
        /// </summary>
        public BinaryReader Reader
        {
            get
            {
                if (this._dataType == BufferDataType.BinaryReader)
                {
                    return this._reader;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.BinaryReader.ToString()}");
                }
            }
        }


        private readonly IntPtr _ptr = IntPtr.Zero;
        /// <summary>
        /// 数据指针
        /// </summary>
        public IntPtr Ptr
        {
            get
            {
                if (this._dataType == BufferDataType.IntPtr)
                {
                    return this._ptr;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.IntPtr.ToString()}");
                }
            }
        }




        private readonly IBufferDataExtend _extend;
        /// <summary>
        /// 扩展数据
        /// </summary>
        public IBufferDataExtend Extend
        {
            get
            {
                if (this._dataType == BufferDataType.Extend)
                {
                    return this._extend;
                }
                else
                {
                    throw new InvalidOperationException($"当前缓存数据类型不是{BufferDataType.Extend.ToString()}");
                }
            }
        }


        /// <summary>
        /// 数据起始偏移位置有效性[true:有效;false:无效]
        /// </summary>
        private bool _offsetValid = true;
        private readonly long _offset;
        /// <summary>
        /// 数据起始偏移位置,小于等于0从头开始
        /// </summary>
        public long Offset
        {
            get
            {
                if (this._offsetValid)
                {
                    return this._offset;
                }
                else
                {
                    throw new InvalidOperationException("数据起始偏移位置值无效");
                }
            }
        }

        /// <summary>
        /// 数据长度值有效性[true:有效;false:无效]
        /// </summary>
        private bool _lengthValid = true;
        private long _length;
        /// <summary>
        /// 数据长度，小于0到结尾
        /// </summary>
        public long Length
        {
            get
            {
                if (this._lengthValid)
                {
                    return this._length;
                }
                else
                {
                    throw new InvalidOperationException("数据长度值无效");
                }
            }
        }

        /// <summary>
        /// 获取或设置与缓存数据关联的用户定义的数据
        /// </summary>
        public object Tag { get; set; }




        /// <summary>
        /// 默认构造函数-每个构造函数都必须调用
        /// </summary>
        /// <param name="dataType"></param>
        private BufferData(BufferDataType dataType)
        {
            this._dataType = dataType;
        }


        private Memory<byte> _memoryBuffer = null;
        /// <summary>
        /// 内存数据
        /// </summary>
        public Memory<byte> MemoryBuffer
        {
            get { return _memoryBuffer; }
        }

        /// <summary>
        /// 构建缓存数据-内存Memory_byte
        /// </summary>
        /// <param name="memoryBuffer">Memory内存缓存buffer数据</param>
        public BufferData(Memory<byte> memoryBuffer)
            : this(BufferDataType.Memory)
        {
            this._memoryBuffer = memoryBuffer;
            this._offsetValid = false;
            this._lengthValid = false;
        }



        /// <summary>
        /// 构建缓存数据-内存byte[]
        /// </summary>
        /// <param name="buffer">内存缓存buffer数据</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(byte[] buffer, int offset = -1, int length = -1)
        : this(BufferDataType.Bytes)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (offset < 0)
            {
                offset = 0;
            }
            else if (offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException($"数据起始偏移位置\"{offset}\"无效,超出范围");
            }

            if (length < 0)
            {
                length = buffer.Length - offset;
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{length}\"无效,超出范围,不能小于0");
            }

            this._bytes = buffer;
            this._offset = offset;
            this._length = length;
        }

        /// <summary>
        /// 构建文件缓存数据-文件
        /// 如果length小于0，在打开文件时需要调用UpdateFileBufferLength方法,否则缓存数据对象中的数据长度值将无效
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(string filePath, long offset = -1, long length = -1)
            : this(BufferDataType.File)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (offset < 0)
            {
                offset = 0;
            }

            if (length < 0)
            {
                this._lengthValid = false;
            }

            this._filePath = filePath;
            this._offset = offset;
            this._length = length;
        }

        /// <summary>
        /// 构建缓存数据-数据流
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(Stream stream, long offset = -1, long length = -1)
            : this(BufferDataType.Stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (offset < 0)
            {
                offset = 0;
            }
            else if (offset > stream.Length)
            {
                throw new ArgumentOutOfRangeException($"数据起始偏移位置\"{offset}\"无效,超出范围,不大于等于流长度");
            }

            if (length < 0)
            {
                length = stream.Length - offset;
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{length}\"无效,超出范围,不能小于0");
            }

            this._stream = stream;
            this._offset = offset;
            this._length = length;
        }

        /// <summary>
        /// 构建缓存数据-二进制读取器
        /// </summary>
        /// <param name="reader">二进制读取器</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(BinaryReader reader, long offset = -1, long length = -1)
            : this(BufferDataType.BinaryReader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (offset < 0)
            {
                offset = 0;
            }
            else if (offset > reader.BaseStream.Length)
            {
                throw new ArgumentOutOfRangeException($"数据起始偏移位置\"{offset}\"无效,超出范围,不大于等于流长度");
            }

            if (length < 0)
            {
                length = reader.BaseStream.Length - offset;
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{length}\"无效,超出范围,不能小于0");
            }

            this._reader = reader;
            this._offset = offset;
            this._length = length;
        }

        /// <summary>
        /// 构建缓存数据-数据指针
        /// </summary>
        /// <param name="ptr">数据指针</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(IntPtr ptr, long offset = 0, long length = -1)
            : this(BufferDataType.IntPtr)
        {
            if (offset < 0)
            {
                offset = 0;
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{length}\"无效,超出范围,不能小于0");
            }

            this._ptr = ptr;
            this._offset = offset;
            this._length = length;
        }

        /// <summary>
        /// 构建缓存数据-扩展数据
        /// </summary>
        /// <param name="data">扩展数据</param>
        /// <param name="offset">数据起始偏移位置,小于等于0从头开始</param>
        /// <param name="length">数据长度，小于0到结尾</param>
        public BufferData(IBufferDataExtend data, long offset = 0, long length = -1)
            : this(BufferDataType.Extend)
        {
            this._extend = data;
            this._offset = offset;
            this._length = length;
        }




        /// <summary>
        /// 更新文件Buffer长度
        /// </summary>
        /// <param name="fileLength">文件大小</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public void UpdateFileBufferLength(long fileLength)
        {
            if (this._dataType != BufferDataType.File)
            {
                throw new InvalidOperationException("仅缓存数据类型为文件时，才允许调用当前方法，其它缓存类型不允许调用");
            }

            if (this._offset > fileLength)
            {
                throw new ArgumentOutOfRangeException($"数据起始偏移位置\"{this._offset}\"无效,超出范围");
            }

            this._length = fileLength - this._offset;
            this._lengthValid = true;
        }

    }


}
